package edu.kit.aifb.ldstream.learner.tasks;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import org.openrdf.model.Statement;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.RepositoryResult;

import edu.kit.aifb.ldstream.env.Environment;
import edu.kit.aifb.ldstream.learner.dao.Instance;
import edu.kit.aifb.ldstream.learner.dao.SimpleStatistics;
import edu.kit.aifb.ldstream.learner.dao.Type;
import edu.kit.aifb.ldstream.stat.util.IDistributionChecker;

public class IndegreeTask extends LearnerTask {

	private SimpleStatistics stats;
	private Map<Type, ArrayList<Instance>> classMap;
	private IDistributionChecker distribCheck;

	public IndegreeTask(SimpleStatistics stats, Map<Type, ArrayList<Instance>> classMap,
			IDistributionChecker distribCheck) {
		this.stats = stats;
		this.classMap = classMap;
		this.distribCheck = distribCheck;
	}


	@Override
	public void run() {
		if(Environment.VERBOSE){
			System.out.println("Started to learn indegree");
		}
		startup();
		calculateIndegree();
		calculateSpecificIndegree();
		shutdown();
		if(Environment.VERBOSE){
			System.out.println("Indegree learned.");
		}
	}

	private void calculateSpecificIndegree(){
		Integer[] indegreeArray;
		int i;
		for(Type t : this.classMap.keySet()){
			i = 0;
			indegreeArray = new Integer[this.classMap.get(t).size()];
			// collect the indegrees of every instance
			for(Instance instance : this.classMap.get(t)){
				indegreeArray[i++] = instance.getIndegree();
			}
			// set the specific indegree distribution for type t
			t.setIndegreeDistribution(this.distribCheck.discrete(indegreeArray, false));
		}
	}

	private void calculateIndegree(){
		int indegree = 0;
		List<Integer> indegreeList = new LinkedList<Integer>();
		for(Type rdfClass : this.classMap.keySet()){
			if(Environment.LOGGING){
				Environment.log.info("counting indegree for type " + rdfClass.getURI().stringValue());
			}
			for(Instance instance : this.classMap.get(rdfClass)){
				try {
					RepositoryResult<Statement> result = this.con.getStatements(null, null, instance.getURI(), false);
					try{

						while(result.hasNext()){
							result.next();
							indegree++;
							instance.incrementIndegree();
						}
						// saving the indegree of every instance
						indegreeList.add(instance.getIndegree());
					}finally{
						result.close();
					}
				} catch (RepositoryException e) {
					e.printStackTrace();
				}
			}
		}
		// indegreeList.size() is the count of instances
		this.stats.setAverageIndegree(((double)indegree) / indegreeList.size()); 
		//converting the list to an array
		Integer[] values = new Integer[indegreeList.size()];
		values = indegreeList.toArray(values);
		// check an save the indegree distribution
		this.stats.setIndegreeDistribution(this.distribCheck.discrete(values, false));

	}

}
